package juc.executors;

import java.util.concurrent.*;
import java.util.stream.IntStream;

public class ExecutorServiceExample3 {

    public static void main(String[] args) {
        //test();
        //testAllowCoreThreadTimeOut();
        //testRemove();
        //testPrestartCoreThread();
        //testPrestartAllThread();
        testThreadPoolAdvice();
    }

    private static void test() {
        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
        System.out.println(executorService.getActiveCount());
        executorService.execute(() -> {
            timeSleep(4);
        });
        timeSleep(1);
        System.out.println(executorService.getActiveCount());
    }

    private static void testAllowCoreThreadTimeOut() {
        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(5);
        //IllegalArgumentException: Core threads must have nonzero keep alive times
        executorService.setKeepAliveTime(10, TimeUnit.SECONDS);
        //允许回收空闲线程，不需要调用shutdown了，会自动销毁
        //和Executors.newCachedThreadPool()一样
        executorService.allowCoreThreadTimeOut(true);
        IntStream.range(0, 5).boxed().forEach(i -> {
            executorService.execute(() -> {
                System.out.println(Thread.currentThread().getName());
                timeSleep(3);
            });
        });
    }

    private static void testRemove() {
        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
        executorService.setKeepAliveTime(10, TimeUnit.SECONDS);
        executorService.allowCoreThreadTimeOut(true);
        IntStream.range(0, 2).boxed().forEach(i -> {
            executorService.execute(() -> {
                timeSleep(6);
                System.out.println(Thread.currentThread().getName() + " finished");
            });
        });
        timeSleep(3);
        Runnable r = () -> {
            System.out.println("i will never be executed");
        };
        executorService.execute(r);
        timeSleep(1);
        //移除队列中线程
        executorService.remove(r);//boolean

    }

    private static void testPrestartCoreThread() {
        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
        System.out.println(executorService.getActiveCount());
        //预启动一个线程，总数不超过corePoolSize
        executorService.prestartCoreThread();
        System.out.println(executorService.getActiveCount());

        executorService.prestartCoreThread();
        System.out.println(executorService.getActiveCount());

        executorService.execute(() -> {
            timeSleep(5);
        });
        executorService.execute(() -> {
            timeSleep(5);
        });
        timeSleep(1);
        executorService.prestartCoreThread();
        System.out.println(executorService.getActiveCount());

    }

    private static void testPrestartAllThread() {
        ThreadPoolExecutor executorService = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);
        executorService.setMaximumPoolSize(3);
        System.out.println(executorService.getActiveCount());

        //预启动不超过corePoolSize个线程
        executorService.prestartAllCoreThreads();
        System.out.println(executorService.getActiveCount());

        timeSleep(1);
        executorService.prestartCoreThread();
        System.out.println(executorService.getActiveCount());

    }

    private static void testThreadPoolAdvice() {
        ExecutorService executorService = new MyThreadPoolExecutor(1, 3, 7, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(2), r -> {
            Thread thread = new Thread(r);
            return thread;
        }, new ThreadPoolExecutor.AbortPolicy());
        executorService.execute(new MyRunnable(1) {
            @Override
            public void run() {
                //System.out.println("===");
                System.out.println(1/0);
            }
        });


    }

    private abstract static class MyRunnable implements Runnable {
        private final int no;

        protected MyRunnable(int no) {
            this.no = no;
        }

        protected int getData() {
            return this.no;
        }
    }

    private static class MyThreadPoolExecutor extends ThreadPoolExecutor {

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        }

        @Override
        protected void beforeExecute(Thread t, Runnable r) {
            System.out.println("init the " + ((MyRunnable) r).getData());
        }

        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            if (null == t){
                System.out.println("successful"+((MyRunnable) r).getData());
            }else{
                t.printStackTrace();
            }
        }

    }

    private static void timeSleep(long time) {
        try {
            TimeUnit.SECONDS.sleep(time);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
